package fr.insee.rome.string.comp;


public class LevenshteinComparator extends AbstractStringComparator implements StringComparator {

	private short
		coutInsertion = 1,
		coutSubstitution = 1,
		coutOmission = 1
	;
	
	private static StringComparator instance = null;
	
	private LevenshteinComparator(){}
	
	public static StringComparator getInstance(){
		if(instance == null){
			instance = new LevenshteinComparator();
		}
		return instance;
	}
	
	public int distance(CharSequence a, CharSequence b) {
		
		int[][] distances = new int[a.length() + 1][b.length() + 1];
		
		for(int i = 0 ; i <= a.length() ; i ++){
			distances[i][0] = i;
		}
		
		for(int j = 0 ; j <= b.length() ; j ++){
			distances[0][j] = j;
		}
		
		for(int i = 1 ; i <= a.length() ; i ++){
			for(int j = 1 ; j <= b.length() ; j ++){
				boolean match = a.charAt(i - 1) == b.charAt(j - 1);
				distances[i][j] = this.min(
					distances[i - 1][j] + (match ? 0 : coutOmission),
					distances[i][j - 1] + (match ? 0 : coutInsertion),
					distances[i - 1][j - 1] + (match ? 0 : coutSubstitution)
				);
			}
		}
		
		int distance = distances[a.length()][b.length()];		
		                                     
		distances = null;
		                                     
		return distance;
	}
	
	private int min(int a, int b, int c){
		
		return Math.min(Math.min(a, b), c);
	}

	public int likeness(CharSequence a, CharSequence b) {
		
		return(
			(this.distance(a, b) * 100) /
			Math.max(a.length(), b.length())
		);
	}
}
